/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Controlador.Service.Simulacion;

import Controlador.Bean.Produccion.DesempenoHistorico;
import Controlador.Bean.Simulacion.FlujoXproducto;
import Controlador.Bean.Simulacion.MaquinaS;
import Controlador.Bean.Simulacion.ProduccionxProducto;
import Controlador.Bean.Simulacion.Rendimiento;
import Controlador.Bean.Simulacion.TipoMaquina;
import Controlador.Bean.Simulacion.Trabajador;
import Data.config.SessionFac;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.apache.ibatis.session.SqlSession;

/**
 *
 * @author Victor
 */
public class ServicioSimulacion {
    
    HashMap<String,String>  maxResultado=null;
    Double  utMAx=null;
    
    public synchronized void actualizarMaximo(HashMap<String,String> resultado,Double utActual){
        if(maxResultado==null ){
               utMAx=utActual;
               maxResultado=resultado;
           }
           else if(utMAx.compareTo(utActual)<0){
               utMAx=utActual;
               maxResultado=resultado;
           }
    }
    
    public HashMap<String, Trabajador> obtenerDatosTrabajadores(SqlSession sqlsession,ArrayList<String> turnos , ArrayList<String> TipoMaquina){
        
        List<HashMap<String,Object>> resultado=sqlsession.selectList("Data.Simulacion.ServicioSimulacion.obtenerTrabajadores");
        
        HashMap<String,Trabajador> resultadoFinal= new HashMap<>();
        String codUsuario=null;
        String nombUsuario= null;
        Trabajador trabajador= null;
        HashMap<String,Rendimiento>  rendimientos=null;  
        int contador=0;
        int i;
        for(i=0;i<resultado.size();i++){
            if(!((String)resultado.get(i).get("codigo")).equals(codUsuario)){               
                if(contador<8 && codUsuario!=null ){
                    for(int l=0;l<turnos.size();l++){
                        for(int m=0;m<TipoMaquina.size();m++){
                            if(rendimientos.get(TipoMaquina.get(m))==null) rendimientos.put(TipoMaquina.get(m), new Rendimiento());
                            if(rendimientos.get(TipoMaquina.get(m)).getPorTurno()==null) rendimientos.get(TipoMaquina.get(m)).setPorTurno( new  HashMap<String,HashMap<String,Double>>());
                            if(rendimientos.get(TipoMaquina.get(m)).getPorTurno().get(turnos.get(l))==null){
                            HashMap<String,Double> temp= new HashMap<>();
                            temp.put("perdida", 5000.00);
                            temp.put("produccion", 0.00);  
                            rendimientos.get(TipoMaquina.get(m)).getPorTurno().put(turnos.get(l), temp);
                            }
                        
                        }
                    
                    }
                
                }
                 if(codUsuario!=null) {
                    trabajador.setRendimiento(rendimientos);
                    resultadoFinal.put(codUsuario, trabajador);                
                }
                codUsuario=(String)resultado.get(i).get("codigo");
                nombUsuario=(String)resultado.get(i).get("nombre");
                trabajador= new Trabajador();
                trabajador.setCodigo(codUsuario);
                trabajador.setNombre(nombUsuario);
                rendimientos=new HashMap<>(); 
                
                contador=0;
            }
            contador++;
            if(rendimientos.get((String)resultado.get(i).get("tipomaquina"))==null){
                rendimientos.put((String)resultado.get(i).get("tipomaquina"), new Rendimiento());
                HashMap<String,Double> temp= new HashMap<>();
                temp.put("perdida", (double)resultado.get(i).get("perdida"));
                temp.put("produccion", (double)resultado.get(i).get("produccion"));  
                if(rendimientos.get((String)resultado.get(i).get("tipomaquina")).getPorTurno()==null)rendimientos.get((String)resultado.get(i).get("tipomaquina")).setPorTurno( new  HashMap<String,HashMap<String,Double>>());

                rendimientos.get((String)resultado.get(i).get("tipomaquina")).getPorTurno().put((String)resultado.get(i).get("turno"),temp);            
            }
            else{
                HashMap<String,Double> temp= new HashMap<>();
                temp.put("perdida", (double)resultado.get(i).get("perdida"));
                temp.put("produccion", (double)resultado.get(i).get("produccion")); 
                if(rendimientos.get((String)resultado.get(i).get("tipomaquina")).getPorTurno()==null)rendimientos.get((String)resultado.get(i).get("tipomaquina")).setPorTurno( new  HashMap<String,HashMap<String,Double>>());
                rendimientos.get((String)resultado.get(i).get("tipomaquina")).getPorTurno().put((String)resultado.get(i).get("turno"),temp);                            
            }            
        }
        
        
                if(contador<8 && codUsuario!=null ){
                    for(int l=0;l<turnos.size();l++){
                        for(int m=0;m<TipoMaquina.size();m++){
                            if(rendimientos.get(TipoMaquina.get(m))==null) rendimientos.put(TipoMaquina.get(m), new Rendimiento());
                            if(rendimientos.get(TipoMaquina.get(m)).getPorTurno()==null) rendimientos.get(TipoMaquina.get(m)).setPorTurno( new  HashMap<String,HashMap<String,Double>>());
                            if(rendimientos.get(TipoMaquina.get(m)).getPorTurno().get(turnos.get(l))==null){
                            HashMap<String,Double> temp= new HashMap<>();
                            temp.put("perdida", 5000.00);
                            temp.put("produccion", 0.00);  
                            rendimientos.get(TipoMaquina.get(m)).getPorTurno().put(turnos.get(l), temp);
                            }
                        
                        }
                    
                    }
                
                }
                 if(codUsuario!=null) {
                    trabajador.setRendimiento(rendimientos);
                    resultadoFinal.put(codUsuario, trabajador);                
                }                             
        return resultadoFinal;
    }
    
    public TreeMap<String, String> obtenerTipoMaquina(SqlSession sqlsession){
        
        List<TipoMaquina> listaTipoMaquina=sqlsession.selectList("Data.Simulacion.ServicioSimulacion.obtenerTiposMaquina");
        TreeMap<String,String> tipos=new TreeMap<>();
        for(int i=0;i<listaTipoMaquina.size();i++){
            tipos.put(listaTipoMaquina.get(i).getCodigo(), listaTipoMaquina.get(i).getNombre());
        }        
        
        return tipos;
    }
    
    public HashMap<String, MaquinaS> obtenerMaquina(SqlSession sqlsession){
            
            List<MaquinaS>  maquinas=sqlsession.selectList("Data.Simulacion.ServicioSimulacion.obtenerMaquinas","codigo");
            
            HashMap<String, MaquinaS> resultado= new HashMap<>();
            for(int i=0;i<maquinas.size();i++){
                resultado.put(maquinas.get(i).getCodigo(), maquinas.get(i));
            }
            
        return resultado;
    }
    public List<String> obtenerTurnos(SqlSession sqlsession){
        
        List<String> turnos=sqlsession.selectList("Data.Simulacion.ServicioSimulacion.obtenerTurnos");
        
        return turnos;
    }
    
     public Map<String,HashMap<String,Object>> obtenerTurnosC(SqlSession sqlsession){
        
        Map<String,HashMap<String,Object>> turnos=sqlsession.selectMap("Data.Simulacion.ServicioSimulacion.obtenerTurnosC","idturno");
        
        return turnos;
    }
     
     public Map<String,HashMap<String,Object>> obtenerNombProds(SqlSession sqlsession){
        
        Map<String,HashMap<String,Object>> prods=sqlsession.selectMap("Data.Simulacion.ServicioSimulacion.obtenerNombreProds","idproducto");
        
        return prods;
    }
     
    
    public Map<String,HashMap<String,Object>> obtenerDatosTrabajador(SqlSession sqlsession){
        
        Map<String,HashMap<String,Object>> trabs=sqlsession.selectMap("Data.Simulacion.ServicioSimulacion.obtenerDatoTrabajador","idempleado");
        
        return trabs;
    }
    
    
    public List<HashMap<String,Object>> obtenerPlanDeVentas(java.util.Date fecha,SqlSession sqlsession){
        
        List<HashMap<String,Object>> PlanDeVentas=sqlsession.selectList("Data.Simulacion.ServicioSimulacion.obtenerPlanDeVemtas",fecha);
        
        return PlanDeVentas;
    }
    
    public  HashMap<String,FlujoXproducto> obtenerReceta(List<HashMap<String,Object>>  planV,SqlSession sqlsession){
        
        ArrayList<String> codProds= new ArrayList<>();
        for(int i=0;i<planV.size();i++){
            codProds.add((String)planV.get(i).get("idproducto"));
        }
        List<HashMap<String,Object>> resultado=sqlsession.selectList("Data.Simulacion.ServicioSimulacion.obtenerRecetasxProductoFinal",codProds);
        int contador=0;
        Double cantCarry=0.00;
        Integer ordenActual=-1;
        Double prop=0.00;
        String codProdAct=null;
        FlujoXproducto flujo=new FlujoXproducto();
        HashMap<String,FlujoXproducto> resultadoFinal= new HashMap<>();
        for(int i=0;i<resultado.size();i++){
            HashMap<String,Object> linea=resultado.get(i);
            if(ordenActual==-1) ordenActual=(Integer)linea.get("orden");            
            if(codProdAct==null || !codProdAct.equals((String)linea.get("codigo"))){
                if(codProdAct!=null){
                    Collections.reverse(flujo.getCodIng());
                    Collections.reverse(flujo.getCant());
                    resultadoFinal.put(codProdAct, flujo);
                }
                codProdAct=(String)linea.get("codigo");
                flujo= new FlujoXproducto();                
                flujo.setCodIng(new ArrayList<String>());
                flujo.setCant(new ArrayList<Double>());
                contador=0;
                ordenActual=(Integer)linea.get("orden"); 
            }
            if(ordenActual.compareTo((Integer)linea.get("orden"))!=0){
                contador++;
                ordenActual=(Integer)linea.get("orden");
            }
            if(contador!=0){
                if(((String)linea.get("es")).equals("S")){
                    flujo.getCodIng().add(((String)linea.get("tipo"))+"."+((String)linea.get("codigoing")));
                    flujo.getCant().add(cantCarry);  
                    prop=flujo.getCant().get(flujo.getCant().size()-1)/(Double)linea.get("cant");                    
                }
                else
                    {   
                        cantCarry=(Double)linea.get("cant")*prop;
                       //flujo.getCodIng().add(((String)linea.get("tipo"))+"."+((String)linea.get("codigoing")));
                       // flujo.getCant().add((Double)linea.get("cant")*prop);                        
                    }
            
            }else{
                if(((String)linea.get("es")).equals("S")){
                    flujo.getCodIng().add(((String)linea.get("tipo"))+"."+((String)linea.get("codigoing")));
                    flujo.getCant().add((Double)linea.get("cant"));                            
                }
                else {
                    cantCarry=(Double)linea.get("cant");
                    //flujo.getCodIng().add(((String)linea.get("codigoing")));
                    //flujo.getCant().add((Double)linea.get("cant"));                            
                }
            }
            
            
            
        }
        Collections.reverse(flujo.getCodIng());
        Collections.reverse(flujo.getCant());
        resultadoFinal.put(codProdAct, flujo);
        
        return resultadoFinal;
    }
    
    public HashMap<String,Object> ejecutarAlgoritmo(Date date){
        AlgMemetico ALGORITMO= new AlgMemetico();  
        ServicioSimulacion servSimulacion= new ServicioSimulacion();
        String imageName = "%02d";
        HashMap<String,Object> resultados= new HashMap<>();
        Calendar calendarA = Calendar.getInstance(); 
        

        HashMap<String,Integer> resumenProduccionxTurnoxTipoMaquina= new HashMap<>();
        HashMap<String,Integer> resumenPerdidaxTurnoxTipoMaquina = new HashMap<>();
              
        //Se cargan los trabajadores, maquinas y tipo de maquinas
        SqlSession sqlsession = SessionFac.SessionFactory().openSession();
        HashMap<String, Trabajador> trabajadores=null;
        HashMap<String, MaquinaS> maquinas=null;
        TreeMap<String,String> tipos=null;
        List<HashMap<String,Object>> planVentasOrig=null;
        HashMap<String,FlujoXproducto> flujosxProducto=null;
        List<String> turnos=null;
        String error="";
        
                
        try{        
        maquinas=servSimulacion.obtenerMaquina(sqlsession);
        tipos=servSimulacion.obtenerTipoMaquina(sqlsession);
        turnos= servSimulacion.obtenerTurnos(sqlsession); 
        trabajadores= servSimulacion.obtenerDatosTrabajadores(sqlsession,new ArrayList<String>(turnos),new ArrayList<String>(tipos.keySet()));
        planVentasOrig=this.obtenerPlanDeVentas(date, sqlsession);
        flujosxProducto=this.obtenerReceta(planVentasOrig, sqlsession);
        }
        catch(Exception e){
        error+="-Error en la obtencion de datos\n";
        }
        finally{
            sqlsession.close();
            
        }                
        if(maquinas==null || maquinas.isEmpty()) error+="-Lista de maquinas vacia\n";
        if(tipos==null || tipos.isEmpty()) error+="-Lista de tipos vacia\n";
        if(turnos==null || turnos.isEmpty()) error+="-Lista de turnos vacia\n";
        if(trabajadores==null || trabajadores.isEmpty()) error+="-Lista de trabajadores vacia\n";
        if((maquinas!=null && maquinas.isEmpty())&&(turnos!=null && turnos.isEmpty())&&((trabajadores!=null && trabajadores.isEmpty()))&&trabajadores.size()<(maquinas.size()*turnos.size())) error+="-Numero insuficiente de trabajadores\n";
        if(planVentasOrig==null || planVentasOrig.isEmpty()) error+="-No se ha encontrado un plan de ventas\n";
        if((planVentasOrig!=null && !planVentasOrig.isEmpty()) && (flujosxProducto==null || flujosxProducto.isEmpty())) error+="-No se ha encontrado la receta de los productos en el plan de ventas\n";
        if((planVentasOrig!=null && planVentasOrig.isEmpty())&&(flujosxProducto!=null && flujosxProducto.isEmpty()) && planVentasOrig.size()!=flujosxProducto.size()) error+="-No se han encontrado recetas para algunos productos del plan de ventas\n";
        
        
        if(!error.isEmpty()){
         resultados.put("error", error);
         return resultados;
        }
        
        //contar los dias en el mes
        //v1.0
        calendarA.setTime(date);
        Integer numeroDias=calendarA.getActualMaximum(Calendar.DAY_OF_MONTH);
        Integer prop=0;
        HashMap<String,Integer> planProdXTurno= new HashMap<>();
        for(int i=0;i<planVentasOrig.size();i++){
            prop=Long.valueOf(((Long)planVentasOrig.get(i).get("cantidadfinal"))/(turnos.size()*numeroDias)).intValue();
            ArrayList<Double> cantidades=flujosxProducto.get(planVentasOrig.get(i).get("idproducto")).getCant();
            ArrayList<String> productos=flujosxProducto.get(planVentasOrig.get(i).get("idproducto")).getCodIng();
            for(int k=(cantidades.size()-1);k>=0;k--){                
                planProdXTurno.put(productos.get(k).split("\\.")[0], ((planProdXTurno.get(productos.get(k).split("\\.")[0])!=null? planProdXTurno.get(productos.get(k).split("\\.")[0]):0)+(cantidades.get(k).intValue()*prop)));
            }        
        }
        
        
        int cores = Runtime.getRuntime().availableProcessors();
        cores=cores%5;
        ExecutorService taskExecutor = Executors.newFixedThreadPool(cores);
        for(int t=0;t<cores;t++){
                   taskExecutor.execute(new HiloAlgoritmo(trabajadores, maquinas, tipos, planVentasOrig, flujosxProducto, turnos,planProdXTurno, this));
        }
        
        taskExecutor.shutdown();
        try {
            taskExecutor.awaitTermination(5, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            resultados.put("error", "-El algoritmo se ha demorado mas de lo permitido por favor verifique las capacidades de procesamiento de su equipo");
            return resultados;
        }
        ArrayList<DesempenoHistorico> resultadoFinal= new ArrayList<>();
        List<HashMap<String,Object>> planVentasCopia=new ArrayList<HashMap<String,Object>>();
        for(int i=0;i<planVentasOrig.size();i++){
            planVentasCopia.add((HashMap<String,Object>)planVentasOrig.get(i).clone());
        }
             TreeMap<String,String> auxiliar=new TreeMap<>(maxResultado);
           Iterator<Map.Entry<String,String>> it = auxiliar.entrySet().iterator();
           
           HashMap<String,DesempenoHistorico> resultadoFinalH= new HashMap<>();
               while(it.hasNext()){               
                DesempenoHistorico aux= new DesempenoHistorico();
                Map.Entry<String,String> entry= it.next();
                aux.setIdEmpleadoOp(entry.getValue());
                String tipomaquina=maquinas.get(entry.getKey().split("\\.")[1]).getTipo();
                aux.setIdMaquina(tipomaquina);
                String turno=entry.getKey().split("\\.")[0];
                aux.setIdTurno(turno);  
                aux.setFecha(date);
                aux.setIdTipoMaquina(entry.getKey().split("\\.")[1]);
                aux.setPerdida(trabajadores.get(entry.getValue()).getRendimiento().get(maquinas.get(entry.getKey().split("\\.")[1]).getTipo()).getPorTurno().get(entry.getKey().split("\\.")[0]).get("perdida"));
                aux.setProduccion(trabajadores.get(entry.getValue()).getRendimiento().get(maquinas.get(entry.getKey().split("\\.")[1]).getTipo()).getPorTurno().get(entry.getKey().split("\\.")[0]).get("produccion"));
                resultadoFinalH.put(aux.getIdEmpleadoOp(), aux);
                resultadoFinal.add(aux);
                 }           
               for(int k=0;k<resultadoFinal.size();k++){
                   DesempenoHistorico aux= resultadoFinal.get(k);                   
                   String temp=aux.getIdTurno()+"."+aux.getIdMaquina();
                   resumenProduccionxTurnoxTipoMaquina.put(temp, (resumenProduccionxTurnoxTipoMaquina.get(temp)==null?0:resumenProduccionxTurnoxTipoMaquina.get(temp)+Double.valueOf(aux.getProduccion()).intValue()));
                   resumenPerdidaxTurnoxTipoMaquina.put(temp, (resumenPerdidaxTurnoxTipoMaquina.get(temp)==null?0:resumenPerdidaxTurnoxTipoMaquina.get(temp)+Double.valueOf(aux.getPerdida()).intValue()));
               }
               
               TreeMap<Date, HashMap<String, HashMap<String, ArrayList<ProduccionxProducto>>>> resultadoPLanificacion=planificacion(resultadoFinal,turnos,new ArrayList<String>(tipos.keySet()),date,planVentasCopia,flujosxProducto);                                    
               if(resultadoPLanificacion==null){
                   resultados.put("error", "-La receta cargada es inconsistente");
                    return resultados;
               }
               
               int estado=0;
               for(int i=0;i<planVentasOrig.size();i++){
                   if(planVentasCopia.get(i).get("cantidadfinal")==0){
                       estado=Math.max(estado, 0);
                   }
                   else if((Long)planVentasCopia.get(i).get("cantidadfinal")>0 && (((Long)planVentasCopia.get(i).get("cantidadfinal"))<((Long)planVentasOrig.get(i).get("cantidadfinal")))){
                       estado=Math.max(estado, 1);
                   }
                   else if(((Long)planVentasCopia.get(i).get("cantidadfinal"))==((Long)planVentasOrig.get(i).get("cantidadfinal"))){
                       estado=Math.max(estado, 2);
                   }                   
               }
               String[] mensaje={"Se puedo completar al 100% el plan de ventas propuesto","Se puedo completar parcialmente el plan de ventas propuesto","No se pudo producir ningun producto del plan de ventas"};
               
               for(int i=0;i<resultadoFinal.size();i++){
                   trabajadores.remove(resultadoFinal.get(i).getIdEmpleadoOp());                   
               }
               
               resultados.put("planProd", resultadoPLanificacion);
               resultados.put("asigHM", resultadoFinal);
               resultados.put("turnos", turnos);        
               resultados.put("asigHMHS", resultadoFinalH);        
               resultados.put("planVentasOrig", planVentasOrig);
               resultados.put("planVentasFaltante", planVentasCopia);
               resultados.put("trabajadores", trabajadores);              
                
    return resultados;
    } 
    public static void writeToFile(String pFilename, StringBuilder pData) throws IOException {  
        BufferedWriter out = new BufferedWriter(new FileWriter(pFilename));  
        out.write(pData.toString());  
        out.flush();  
        out.close();  
    }  
    
    public HashMap<String,HashMap<String,ArrayList<DesempenoHistorico>>> clonarResultadoFinal(ArrayList<DesempenoHistorico> resultadoFinal){
        HashMap<String,HashMap<String,ArrayList<DesempenoHistorico>>> resultadoFinalH= new HashMap<>();
        for(int i=0;i<resultadoFinal.size();i++){               
                DesempenoHistorico aux= resultadoFinal.get(i).clonar();                
                if(resultadoFinalH.get(aux.getIdTurno())==null) resultadoFinalH.put(aux.getIdTurno(), new HashMap<String,ArrayList<DesempenoHistorico>>());
                if(resultadoFinalH.get(aux.getIdTurno()).get(aux.getIdMaquina())==null)resultadoFinalH.get(aux.getIdTurno()).put(aux.getIdMaquina(),new ArrayList<DesempenoHistorico>());
                resultadoFinalH.get(aux.getIdTurno()).get(aux.getIdMaquina()).add(aux);                
        }
        return resultadoFinalH;
    }
    
    public TreeMap<Date, HashMap<String, HashMap<String, ArrayList<ProduccionxProducto>>>> planificacion(ArrayList<DesempenoHistorico> resultadoFinalH, List<String> turnos,List<String> Tipos,java.util.Date date, List<HashMap<String,Object>> planVentasOrig,HashMap<String,FlujoXproducto> flujosxProducto){        
        List<HashMap<String,Object>> planVentas=null;
        HashMap<String,HashMap<String,ArrayList<DesempenoHistorico>>> resultadoFinalHC=null;
        planVentas = new ArrayList<HashMap<String,Object>>(planVentasOrig);        
               
        Calendar calendarA = Calendar.getInstance();  
        Calendar calendarB = Calendar.getInstance();  
        calendarA.setTime(date);          
        calendarA.set(Calendar.DAY_OF_MONTH, 1);  
        Date firstDayOfMonth = calendarA.getTime();          
        calendarA.add(Calendar.MONTH, 1);  
        calendarA.add(Calendar.DATE, -1);  
        Date lastDayOfMonth = calendarA.getTime();  
        calendarB.setTime(lastDayOfMonth);
        calendarB.add(Calendar.DATE, 1);  
        calendarA.setTime(firstDayOfMonth);
        String productoxFaseActual = null;
        ArrayList<DesempenoHistorico> EficienciasXTipoMaquinaXturno;
        Double requiere=0.0;
        Double requiere1=0.0;
        Double requiere2=0.0;
        Double requiereSig=0.0;
        Double produce=0.0;
        Integer bottleneck=Integer.MIN_VALUE;
        Double bottleneckCant=Double.NaN;
        boolean inicio=false;
        boolean finalizar=false;
         TreeMap<java.util.Date,HashMap<String,HashMap<String, ArrayList<ProduccionxProducto>>>> produccionxDiaxTipoMaquina= new TreeMap<>();
        for(calendarA.setTime(firstDayOfMonth);!calendarA.equals(calendarB);calendarA.add(Calendar.DATE, 1)){
            resultadoFinalHC= this.clonarResultadoFinal(resultadoFinalH);
            HashMap<String,HashMap<String, ArrayList<ProduccionxProducto>>> asignacionxTurno= new HashMap<>();
            for(int j=0;j<turnos.size();j++){                
                asignacionxTurno.put(turnos.get(j), new HashMap<String, ArrayList<ProduccionxProducto>>());
                for(int i=0;i<planVentas.size();i++){
                    inicio=false;
                    finalizar=false;
                    Double reducirPlanVentas=Double.NaN;
                    FlujoXproducto actual=flujosxProducto.get((String)planVentas.get(i).get("idproducto"));
                    ArrayList<String> listProductosxFase=actual.getCodIng();
                    ArrayList<Double> listCantProductosxFase=actual.getCant();
                    requiere=((Long)planVentas.get(i).get("cantidadfinal")).doubleValue();                    
                    produce=0.0;
                    requiereSig=Double.NEGATIVE_INFINITY;
                    if(requiere.compareTo(0.00)>0)
                    /*Primer intento de aseignacion*/
                    bottleneck=Integer.MIN_VALUE;
                    for(int k=(listProductosxFase.size()-1);k>=0;k--){
                        productoxFaseActual= listProductosxFase.get(k);
                        if(resultadoFinalHC.get(turnos.get(j))!=null)
                        EficienciasXTipoMaquinaXturno=resultadoFinalHC.get(turnos.get(j)).get(productoxFaseActual.split("\\.")[0]);
                        else EficienciasXTipoMaquinaXturno=null;
                        if(requiereSig.compareTo(Double.NEGATIVE_INFINITY)!=0)requiere=requiereSig;
                        requiereSig=0.00;
                        produce=0.00;
                        if(EficienciasXTipoMaquinaXturno!=null && !requiere.equals(0.00))
                        for(int h=0;h<EficienciasXTipoMaquinaXturno.size();h++){
                                Double prodAct=EficienciasXTipoMaquinaXturno.get(h).getProduccion();
                                Double perdAct=EficienciasXTipoMaquinaXturno.get(h).getPerdida();
                                produce+=prodAct;
                           if(requiere.compareTo(produce)<0)
                            {                           
                                produce-=prodAct;
                                Double dif=requiere-produce;
                                perdAct=Math.ceil((perdAct/prodAct)*(dif));                                
                                prodAct=(dif);                                
                                produce+=prodAct;                               
                            }                           
                            requiereSig+=prodAct*(k>0?listCantProductosxFase.get(k-1)/listCantProductosxFase.get(k):1.00);
                            requiereSig+=perdAct*(k>0?listCantProductosxFase.get(k-1)/listCantProductosxFase.get(k):1.00);
                             
                           if(requiere.compareTo(produce)==0  ) {                                
                                break;
                            }     
                            
                        }
                            if(k==(listProductosxFase.size()-1)){
                                requiere1=produce;                                    
                            }
                            if(produce.compareTo(requiere)<0 &&k<(listProductosxFase.size()-1)) {
                                inicio=true;
                                bottleneck=k;
                                bottleneckCant=produce;
                            }
                     }
                    /*Si el primer intento fallo se corrige la produccion*//*se va a forzar el fallo-se me acabaron las ideas*/
                        
                        Double disponible=Double.NaN;
                        Double aumento=Double.NaN;
                        if(bottleneck.compareTo(Integer.MIN_VALUE)!=0){
                        for(int k=bottleneck.intValue()+1;k<listProductosxFase.size();k++){
                            if(disponible.compareTo(Double.NaN)==0)disponible=bottleneckCant;
                            else disponible=produce;
                            productoxFaseActual= listProductosxFase.get(k);
                            if(resultadoFinalHC.get(turnos.get(j))!=null)
                            EficienciasXTipoMaquinaXturno=resultadoFinalHC.get(turnos.get(j)).get(productoxFaseActual.split("\\.")[0]);
                            else EficienciasXTipoMaquinaXturno=null;
                            produce=0.00;
                            requiereSig=0.00;       
                            if(EficienciasXTipoMaquinaXturno!=null)
                            for(int h=0;h<EficienciasXTipoMaquinaXturno.size();h++){
                              Double prodAct=EficienciasXTipoMaquinaXturno.get(h).getProduccion();
                              Double perdAct=EficienciasXTipoMaquinaXturno.get(h).getPerdida();
                              aumento=(prodAct+perdAct)*(k>0?listCantProductosxFase.get(k-1)/listCantProductosxFase.get(k):1.00);                                                            
                              produce+=prodAct;                               
                              Double dif=disponible-requiereSig;                             
                              if(aumento.compareTo(dif)>0){
                                  
                                  
                                  produce-=prodAct; 
                                  Double proporcion=perdAct/prodAct;
                                  prodAct=Math.floor(((dif)/(k>0?listCantProductosxFase.get(k-1)/listCantProductosxFase.get(k):1.00))/(1.00+(proporcion)));
                                  perdAct=Math.ceil(proporcion*prodAct);                                  
                                  produce+=prodAct; 
                                                                    
                                  }
                              
                              requiereSig+=(prodAct+perdAct)*(k>0?listCantProductosxFase.get(k-1)/listCantProductosxFase.get(k):1.00);                              
                              dif=disponible-requiereSig;  
                              if(dif.compareTo(0.00)<0){
                                  requiereSig-=(prodAct+perdAct)*(k>0?listCantProductosxFase.get(k-1)/listCantProductosxFase.get(k):1.00);
                                  produce-=prodAct; 
                                  Double proporcion=perdAct/prodAct;
                                  prodAct+=Math.floor(((dif)/(k>0?listCantProductosxFase.get(k-1)/listCantProductosxFase.get(k):1.00))/(1.00+(proporcion)));
                                  perdAct=Math.ceil(proporcion*prodAct);                                  
                                  produce+=prodAct; 
                                  requiereSig+=(prodAct+perdAct)*(k>0?listCantProductosxFase.get(k-1)/listCantProductosxFase.get(k):1.00);                                  
                              }
                              if(requiereSig.compareTo(disponible)==0 || disponible.compareTo(requiereSig+2*(k>0?listCantProductosxFase.get(k-1)/listCantProductosxFase.get(k):1.00))<=0){
                                  break;
                              }
                            }
                            
                        }
                         disponible=produce;
                         requiere=disponible;   
                        }
                        else {
                         requiere=((Long)planVentas.get(i).get("cantidadfinal")).doubleValue();    
                        }
                     /*Se hace un segundo intento de asignacion*/
                                        
                        produce=0.0;
                        requiereSig=Double.NEGATIVE_INFINITY;
                        bottleneck=Integer.MIN_VALUE;
                        bottleneckCant=Double.NaN;
                        requiere2=requiere;
                         for(int k=(listProductosxFase.size()-1);k>=0;k--){                             
                                productoxFaseActual= listProductosxFase.get(k);
                                if(resultadoFinalHC.get(turnos.get(j))!=null)
                                EficienciasXTipoMaquinaXturno=resultadoFinalHC.get(turnos.get(j)).get(productoxFaseActual.split("\\.")[0]);
                                else EficienciasXTipoMaquinaXturno=null;
                                if(requiereSig.compareTo(Double.NEGATIVE_INFINITY)!=0)requiere=requiereSig;
                                requiereSig=0.00;
                                produce=0.00;
                                if(EficienciasXTipoMaquinaXturno!=null && !requiere.equals(0.00))
                                for(int h=0;h<EficienciasXTipoMaquinaXturno.size();h++){
                                        Double prodAct=EficienciasXTipoMaquinaXturno.get(h).getProduccion();
                                        Double perdAct=EficienciasXTipoMaquinaXturno.get(h).getPerdida();
                                        produce+=prodAct;
                                   if(requiere.compareTo(produce)<0)
                                    {                           
                                        produce-=prodAct;
                                        Double dif=requiere-produce;
                                        perdAct=Math.ceil((perdAct/prodAct)*(dif));                                
                                        prodAct=(dif);                                
                                        produce+=prodAct;                               
                                    }                           
                                    requiereSig+=prodAct*(k>0?listCantProductosxFase.get(k-1)/listCantProductosxFase.get(k):1.00);
                                    requiereSig+=perdAct*(k>0?listCantProductosxFase.get(k-1)/listCantProductosxFase.get(k):1.00);
                                    /*Se guarda la asignacion*/
                                    if(asignacionxTurno.get(turnos.get(j)).get(EficienciasXTipoMaquinaXturno.get(h).getIdEmpleadoOp())==null) asignacionxTurno.get(turnos.get(j)).put(EficienciasXTipoMaquinaXturno.get(h).getIdEmpleadoOp(), new ArrayList<ProduccionxProducto>());
                                        ProduccionxProducto asignacion= new ProduccionxProducto();
                                        asignacion.setCodProducto(productoxFaseActual);
                                        asignacion.setPerdida(perdAct);
                                        asignacion.setProduccion(prodAct);
                                        EficienciasXTipoMaquinaXturno.get(h).setProduccion(EficienciasXTipoMaquinaXturno.get(h).getProduccion()-prodAct);
                                        EficienciasXTipoMaquinaXturno.get(h).setPerdida(EficienciasXTipoMaquinaXturno.get(h).getPerdida()-perdAct);
                                        if(prodAct.compareTo(0.00)>0){                                         
                                        asignacionxTurno.get(turnos.get(j)).get(EficienciasXTipoMaquinaXturno.get(h).getIdEmpleadoOp()).add(asignacion);
                                        }
                                    /*------------------------*/   
                                   if(requiere.compareTo(produce)==0) {                                
                                        break;
                                    }     

                                }
                                /*Verificado nunca entra en el IF*/
                                    if(produce.compareTo(requiere)<0 && k<(listProductosxFase.size()-1)) {                                        
                                        finalizar=true;
                                        bottleneck=k;
                                        bottleneckCant=produce;
                                        return null;
                                    }
                                /*--------------------------------------*/    
                                 if(k==(listProductosxFase.size()-1)){
                                 reducirPlanVentas=produce;
                                 }   
                          }
                      planVentas.get(i).put("cantidadfinal",(Long)planVentas.get(i).get("cantidadfinal")-reducirPlanVentas.longValue());                                                          
                }    
            }
            produccionxDiaxTipoMaquina.put(calendarA.getTime(), asignacionxTurno);
        }
        
        return produccionxDiaxTipoMaquina;
    }
    
    public List<HashMap<String,Object>> cargarTrabajadores(){
        
        List<HashMap<String,Object>> resultado= new ArrayList<>();
        
        String csvFile = "trabajadores01.csv";
	BufferedReader br = null;
	String line = "";
	String cvsSplitBy = ",";        
        int i=0;
	try {
 
		br = new BufferedReader(new FileReader(csvFile));
		while ((line = br.readLine()) != null) {
		        // use comma as separator
			String[] datos = line.split(cvsSplitBy);
                        HashMap<String,Object> resultadoLinea= new HashMap<>();
                        resultadoLinea.put("tipomaquina", datos[0]);
                        resultadoLinea.put("codigo", datos[1]);
                        resultadoLinea.put("turno", datos[2]);
                        resultadoLinea.put("produccion", Double.parseDouble(datos[3]));
                        resultadoLinea.put("perdida", Double.parseDouble(datos[4]));
                        resultado.add(resultadoLinea);
		}
                
                return resultado;
                
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		if (br != null) {
			try {
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
        return null;

    }

    
    public void guardarSimulacion(List<DesempenoHistorico> asignacion){
        if(asignacion.size()>0){
        SqlSession sqlsession=SessionFac.SessionFactory().openSession();
            try{
                sqlsession.update("Data.Simulacion.ServicioSimulacion.eliminarAsignacionAnterior",asignacion.get(0).getFecha());
                for(int i=0;i<asignacion.size();i++){
                    sqlsession.insert("Data.Simulacion.ServicioSimulacion.guardarAsignacion", asignacion.get(i));
                }
                sqlsession.commit();
            }
            catch(Exception e){
            e.printStackTrace();}
            finally{
                sqlsession.rollback();
                sqlsession.close();
            }
    }
    }
    
}
